package com.tsfyun.scm.service.impl.third;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.constant.LoginConstant;
import com.tsfyun.common.base.dto.WxMiniProgram;
import com.tsfyun.common.base.dto.WxNoticeAttr;
import com.tsfyun.common.base.dto.WxNoticeMessageDTO;
import com.tsfyun.common.base.enums.*;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.scm.config.properties.WxGzhProperties;
import com.tsfyun.scm.config.redis.RedisUtils;
import com.tsfyun.scm.constant.WeiXinConstant;
import com.tsfyun.scm.dto.support.SendWxDTO;
import com.tsfyun.scm.dto.support.WXReplyMessageDTO;
import com.tsfyun.scm.dto.support.WxMessageDTO;
import com.tsfyun.scm.entity.user.Login;
import com.tsfyun.scm.service.third.IWeixinService;
import com.tsfyun.scm.service.third.IWxMessageService;
import com.tsfyun.scm.service.user.ILoginService;
import com.tsfyun.scm.service.user.IPersonService;
import com.tsfyun.scm.stream.send.ScmProcessor;
import com.tsfyun.scm.util.WxMessageContentUtil;
import com.tsfyun.scm.util.WxMessageUtil;
import com.tsfyun.scm.vo.support.WxFocusUserInfoVO;
import com.tsfyun.scm.vo.user.ThreeLoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @CreateDate: Created in 2020/12/23 11:19
 */
@RefreshScope
@Service
@Slf4j
public class WxMessageServiceImpl implements IWxMessageService {

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private ScmProcessor scmProcessor;

    @Resource
    private WxGzhProperties wxGzhProperties;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private IWeixinService weixinService;

    @Autowired
    private IPersonService personService;

    @Value("${weChat.wxccxAppid}")
    private String wxccxAppid;

    @Autowired
    private OrikaBeanMapper beanMapper;

    @Autowired
    private ILoginService loginService;

    @Value("${spring.profiles.active:dev}")
    private String profiles;

    @Override
    public void sendWxNotice(WxNoticeMessageDTO dto) {
        if(StringUtils.isEmpty(dto.getWxgzhOpenid())) {
            log.error("没有绑定微信公众号，不发送通知");
            return;
        }
        if(Objects.equals(profiles,"dev") || Objects.equals(profiles,"test")) {
            return;
        }
        WxMessageDefineTemplate wxMessageDefineTemplate = dto.getWxMessageDefineTemplate();
        LinkedHashMap<String, WxNoticeAttr> params = dto.getParams();
        //验证通知模板参数是否传值
        List<String> paramKeys = wxMessageDefineTemplate.getParakeys();
        for(String paramKey : paramKeys) {
            if(!params.containsKey(paramKey)) {
                log.error("微信消息模板【{}】,没有参数字段【{}】",wxMessageDefineTemplate.getName(),paramKey);
                //throw new ServiceException("微信通知参数错误");
                return;
            }
        }
        threadPoolTaskExecutor.execute(()->{
            SendWxDTO sendWxDTO = new SendWxDTO();
            sendWxDTO.setTouser(dto.getWxgzhOpenid());
            sendWxDTO.setTemplate_id(wxMessageDefineTemplate.getCode());
            sendWxDTO.setUrl(dto.getUrl());
            if(Objects.equals(dto.getIsNavToMiniprogram(),Boolean.TRUE)) {
                WxMiniProgram wxMiniProgram = dto.getMiniprogram();
                wxMiniProgram.setAppid(wxccxAppid);
                if(StringUtils.isEmpty(wxMiniProgram.getPagepath())) {
                    wxMiniProgram.setPagepath("/pages/index/index");
                }
                sendWxDTO.setMiniprogram(wxMiniProgram);
            }
            sendWxDTO.setData(dto.getParams());
            log.info("开始准备发送微信通知，消息内容为【{}】", JSONObject.toJSONString(sendWxDTO));
            scmProcessor.sendWx(sendWxDTO);
        });
    }


    @Override
    public void send2Wx(SendWxDTO dto) {
        String accessToken = weixinService.access_token();
        if(StringUtils.isNotEmpty(accessToken)) {
            String response = HttpRequest.post(StrUtil.format("{}?access_token={}", WeiXinConstant.WEIXIN_TEMPLATE_MESSAGE_URL,accessToken)).addHeaders(new HashMap<String, String>(){{
                put("Content-Type","application/json");
            }}).timeout(wxGzhProperties.getTimeout()).body(JSON.toJSONString(dto)).execute().body();
            log.info("微信通知响应【{}】",response);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String handleEvent(HttpServletRequest request,HttpServletResponse response) {
        String respMessage = "";
        try {
            Map<String, String> requestMap = WxMessageUtil.parseXml(request);
            log.info("解析微信公众号消息内容【{}】",JSONObject.toJSONString(requestMap));
            WxMessageDTO weixinMessageDTO = new WxMessageDTO();
            // 发送方帐号(OpenId)
            weixinMessageDTO.setFromUserName(requestMap.get("FromUserName"));
            // 公众帐号(JWID)
            weixinMessageDTO.setToUserName(requestMap.get("ToUserName"));
            // 消息类型
            weixinMessageDTO.setMsgType(requestMap.get("MsgType"));
            //消息ID
            weixinMessageDTO.setMsgId(requestMap.get("MsgId"));
            //消息内容
            weixinMessageDTO.setContent(requestMap.get("Content"));
            //多媒体ID
            weixinMessageDTO.setMediaId(requestMap.get("MediaId"));
            //菜单key
            weixinMessageDTO.setKey(requestMap.get("EventKey"));
            //Event(事件)
            weixinMessageDTO.setEvent(requestMap.get("Event"));

            //处理事件消息
            WxRequestMessageEventEnum wxRequestType = WxRequestMessageEventEnum.of(weixinMessageDTO.getMsgType());
            if(Objects.isNull(wxRequestType)) {
                log.error("未定义微信请求事件类型【{}】",weixinMessageDTO.getMsgType());
                return "";
            }
            switch (wxRequestType) {
                case EVENT:
                    //获取事件类型
                    WxMessageEventEnum event = WxMessageEventEnum.of(weixinMessageDTO.getEvent());
                    if(Objects.equals(event,WxMessageEventEnum.SUBSCRIBE)) {// 关注订阅
                        //获取用户信息
                        WxFocusUserInfoVO wxFocusUserInfoVO = weixinService.getWxFocusUserInfo(weixinMessageDTO.getFromUserName());
                        if(Objects.isNull(wxFocusUserInfoVO)) {
                            log.info("关注公众号未获取到微信用户信息");
                            //响应信息
                            respMessage = WxMessageContentUtil.wrapFocus(weixinMessageDTO,wxccxAppid);
                            break;
                        }
                        //更新人员表中的微信公众号id
                        if(StringUtils.isNotEmpty(wxFocusUserInfoVO.getUnionid())) {
                            Login thirdLogin = loginService.findByLoginName(wxFocusUserInfoVO.getUnionid());
                            if(Objects.nonNull(thirdLogin)) {
                                personService.subscribeWxgzh(thirdLogin.getPersonId(),wxFocusUserInfoVO.getOpenid());
                            }
                        }
                        // 二维码中参数
                        if(StringUtils.isNotEmpty(weixinMessageDTO.getKey())) {
                            String eventKey = weixinMessageDTO.getKey().replace("qrscene_", "");
                            ThreeLoginVO threeLoginVO = convertWxFocusUserInfoVO(wxFocusUserInfoVO);
                            if(weixinMessageDTO.getKey().contains(LoginConstant.BIND_WEIXIN_PREFIX)) {
                                //登录用户关注微信公众号绑定微信
                                //先判断是否存在人员信息
                                Object threeLoginVOObj = redisUtils.get(LoginConstant.BIND_WEIXIN.concat(eventKey));
                                if(Objects.nonNull(threeLoginVOObj)) {
                                    ThreeLoginVO originThreeLoginVO = beanMapper.map(threeLoginVOObj, ThreeLoginVO.class);
                                    threeLoginVO.setPersonId(originThreeLoginVO.getPersonId());
                                    redisUtils.set(LoginConstant.BIND_WEIXIN.concat(eventKey),threeLoginVO,Long.valueOf(1), TimeUnit.HOURS);
                                } else {
                                    log.error("登录用户绑定微信KEY【{}】已失效，无法绑定",eventKey);
                                }
                            } else if (weixinMessageDTO.getKey().contains(LoginConstant.BIND_WEIXIN_LOGIN_PREFIX)) {
                                //登录用户绑定/换绑微信
                                String cacheKey = LoginConstant.BIND_WEIXIN_LOGIN.concat(eventKey);
                                log.info("绑定换绑微信缓存key【{}】",cacheKey);
                                Object threeLoginVOObj = redisUtils.get(cacheKey);
                                if(Objects.nonNull(threeLoginVOObj)) {
                                    ThreeLoginVO originThreeLoginVO = beanMapper.map(threeLoginVOObj, ThreeLoginVO.class);
                                    threeLoginVO.setPersonId(originThreeLoginVO.getPersonId());
                                    redisUtils.set(LoginConstant.BIND_WEIXIN_LOGIN.concat(eventKey),threeLoginVO,Long.valueOf(1), TimeUnit.HOURS);
                                } else {
                                    log.error("登录用户绑定微信KEY【{}】已失效，无法绑定",eventKey);
                                }
                            } else {
                                //临时登录
                                redisUtils.set(LoginConstant.TEMP_LOGIN.concat(eventKey),threeLoginVO,Long.valueOf(1), TimeUnit.HOURS);
                            }
                        } else {
                            //不带参关注
                        }
                        //响应信息
                        respMessage = WxMessageContentUtil.wrapFocus(weixinMessageDTO,wxccxAppid);
                    } else if (Objects.equals(event,WxMessageEventEnum.SCAN)){ // 已经关注再次扫码
                        // 二维码中参数
                        if(StringUtils.isNotEmpty(weixinMessageDTO.getKey())) {
                            String eventKey = weixinMessageDTO.getKey();
                            //获取用户信息
                            WxFocusUserInfoVO wxFocusUserInfoVO = weixinService.getWxFocusUserInfo(weixinMessageDTO.getFromUserName());
                            if(Objects.isNull(wxFocusUserInfoVO)) {
                                break;
                            }
                            ThreeLoginVO threeLoginVO = convertWxFocusUserInfoVO(wxFocusUserInfoVO);
                            if(weixinMessageDTO.getKey().contains(LoginConstant.BIND_WEIXIN_PREFIX)) {
                                //登录用户关注微信公众号绑定微信
                                //先判断是否存在人员信息
                                Object threeLoginVOObj = redisUtils.get(LoginConstant.BIND_WEIXIN.concat(eventKey));
                                if(Objects.nonNull(threeLoginVOObj)) {
                                    ThreeLoginVO originThreeLoginVO = beanMapper.map(threeLoginVOObj, ThreeLoginVO.class);
                                    threeLoginVO.setPersonId(originThreeLoginVO.getPersonId());
                                    redisUtils.set(LoginConstant.BIND_WEIXIN.concat(eventKey),threeLoginVO,Long.valueOf(1), TimeUnit.HOURS);
                                } else {
                                    log.error("登录用户绑定微信KEY【{}】已失效，无法绑定",eventKey);
                                }
                            } else if (weixinMessageDTO.getKey().contains(LoginConstant.BIND_WEIXIN_LOGIN_PREFIX)) {
                                //登录用户绑定/换绑微信
                                String cacheKey = LoginConstant.BIND_WEIXIN_LOGIN.concat(eventKey);
                                log.info("绑定换绑微信缓存key【{}】",cacheKey);
                                Object threeLoginVOObj = redisUtils.get(cacheKey);
                                if(Objects.nonNull(threeLoginVOObj)) {
                                    ThreeLoginVO originThreeLoginVO = beanMapper.map(threeLoginVOObj, ThreeLoginVO.class);
                                    threeLoginVO.setPersonId(originThreeLoginVO.getPersonId());
                                    redisUtils.set(LoginConstant.BIND_WEIXIN_LOGIN.concat(eventKey),threeLoginVO,Long.valueOf(1), TimeUnit.HOURS);
                                } else {
                                    log.error("登录用户绑定微信KEY【{}】已失效，无法绑定",eventKey);
                                }
                            } else {
                                //临时登录
                                redisUtils.set(LoginConstant.TEMP_LOGIN.concat(weixinMessageDTO.getKey()),threeLoginVO,Long.valueOf(1), TimeUnit.HOURS);
                            }
                        }
                        //响应信息
                        sendSuccess(response);
                        /*
                        WXReplyMessageDTO replyMessageDTO =  new WXReplyMessageDTO(weixinMessageDTO.getFromUserName(),WxResponseMessageEventEnum.TEXT.getCode(),"扫码成功");
                        weixinService.sendCustomsMessage(replyMessageDTO);
                         */
                        respMessage = request.getParameter("echostr");
                    } else if (Objects.equals(event,WxMessageEventEnum.UNSUBSCRIBE)){ //取消关注
                        WxFocusUserInfoVO wxFocusUserInfoVO = weixinService.getWxFocusUserInfo(weixinMessageDTO.getFromUserName());
                        if(Objects.isNull(wxFocusUserInfoVO)) {
                            break;
                        }
                        //人员表的公众号id置为空
                        personService.unsubscribeWxgzh(wxFocusUserInfoVO.getOpenid());
                    } else if (Objects.equals(event,WxMessageEventEnum.CLICK)) { //自定义点击菜单
                        String eventKey = weixinMessageDTO.getKey();
                        if(Objects.equals(eventKey, WxMenuClickKeyEnum.XG_GYWM001_link.getCode())) {
                            //响应信息
                            sendSuccess(response);
                            String content = WxMessageContentUtil.wrapLink();
                            WXReplyMessageDTO replyMessageDTO =  new WXReplyMessageDTO(weixinMessageDTO.getFromUserName(),WxResponseMessageEventEnum.TEXT.getCode(),content);
                            weixinService.sendCustomsMessage(replyMessageDTO);
                        } else if (Objects.equals(eventKey,WxMenuClickKeyEnum.XG_GYWM001_introduce.getCode())) { //企业介绍
                            //响应信息
                            sendSuccess(response);
                            String content = WxMessageContentUtil.wrapIntroduce();
                            WXReplyMessageDTO replyMessageDTO =  new WXReplyMessageDTO(weixinMessageDTO.getFromUserName(),WxResponseMessageEventEnum.TEXT.getCode(),content);
                            weixinService.sendCustomsMessage(replyMessageDTO);
                        }
                        respMessage = request.getParameter("echostr");
                    }  else if (Objects.equals(event,WxMessageEventEnum.VIEW)) { //自定义菜单跳转

                    }
                    break;
                case IMAGE:
                case LINK:
                case LOCATION:
                case VOICE:
                case SHORTVIDEO:
                case TEXT:
                    //响应信息
                    sendSuccess(response);
                    respMessage = request.getParameter("echostr");
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            log.error("处理微信公众号事件异常",e);
        }
        return respMessage;
    }

    private ThreeLoginVO convertWxFocusUserInfoVO(WxFocusUserInfoVO vo){
        ThreeLoginVO threeLoginVO = new ThreeLoginVO();
        threeLoginVO.setOpenId(vo.getOpenid());
        threeLoginVO.setUnionId(vo.getUnionid());
        threeLoginVO.setNickName(vo.getNickname());
        threeLoginVO.setGender(vo.getSex());
        threeLoginVO.setAvatarUrl(vo.getHeadimgurl());
        threeLoginVO.setSource("wxgzh");
        return threeLoginVO;
    }

    /**
     * 回复服务器
     * 假如服务器无法保证在五秒内处理并回复，必须做出下述回复，这样微信服务器才不会对此作任何处理，并且不会发起重试（这种情况下，可以使用客服消息接口进行异步回复），否则，将出现严重的错误提示。详见下面说明：
     * 1、直接回复success（推荐方式） 2、直接回复空串（指字节长度为0的空字符串，而不是XML结构体中content字段的内容为空）
     * @param response
     * @throws Exception
     */
    private void sendSuccess(HttpServletResponse response) throws Exception {
        response.setContentType("text/html;charset=utf-8"); //设置输出编码格式
        String result = "success";
        response.getWriter().println(result);
        response.getWriter().flush();
        response.getWriter().close();
    }



}

